﻿using System;
using System.Xml.Serialization;
using System.IO;
using System.Windows.Forms;
using System.Collections.Generic;

namespace JetLoginTool.Engine
{
	/// <summary>
	/// Stores the settings that the JetEngine uses
	/// </summary>
	public class JetSettings
	{
		#region Constants
		private const string SETTINGS_FILE = "settings.config";
		#endregion
		#region Fields
		private static readonly FileInfo settingsFile = new FileInfo(string.Format("{0}\\{1}", Application.LocalUserAppDataPath, SETTINGS_FILE));

		private string username = "";
		private string password = "";
		private bool savePassword = true;
		private bool saveUsername = true;
		private bool checkForNewVersions = true;
		private bool loginOnStart = true;
		private bool startMinimised = true;
		private bool startWithWindows = true;
		private int successBalloonTimeout = 60;
		private int errorBalloonTimeout = 300;
		private string locationName = "";
		#endregion
		#region Constructors
		/// <summary>
		/// Default Constructor
		/// </summary>
		public JetSettings()
		{
			SuppressSaving = true;
			CurrentLocation = null;
			Locations = Location.loadLocations();
			locationName = Locations[0].Name;
		}

		/// <summary>
		/// Copy Constructor
		/// </summary>
		/// <param name="inJetSettings">JetSettings to copy</param>
		public JetSettings(JetSettings inJetSettings)
		{
			SuppressSaving = true;
			username = inJetSettings.Username;
			password = inJetSettings.PlainPassword;
			saveUsername = inJetSettings.SaveUsername;
			savePassword = inJetSettings.SavePassword;
			checkForNewVersions = inJetSettings.CheckForNewVersions;
			loginOnStart = inJetSettings.LoginOnStart;
			startMinimised = inJetSettings.StartMinimised;
			startWithWindows = inJetSettings.StartWithWindows;
			locationName = inJetSettings.LocationName;
			SetCurrentLocation();
			successBalloonTimeout = inJetSettings.SuccessBalloonTimeout;
			errorBalloonTimeout = inJetSettings.ErrorBalloonTimeout;
			Locations = Location.loadLocations();
		}
		#endregion
		#region Properties
		/// <summary>
		/// Username to use when logging in
		/// </summary>
		public string Username
		{
			get { return username; }
			set
			{
				if (username != value)
				{
					username = value;
					saveSettingsFromChange();
					RaiseCredentialsChangedEvent();
				}
			}
		}

		/// <summary>
		/// Password to use when logging in
		/// </summary>
		public string Password
		{
			get
			{ return EncryptionHandler.EncryptString(password); }
			set
			{
				string decryptValue = EncryptionHandler.DecryptString(value);
				if (password != decryptValue)
				{
					password = decryptValue;
					saveSettingsFromChange();
					RaiseCredentialsChangedEvent();
				}
			}
		}

		/// <summary>
		/// Gets the plain-text version of the password
		/// </summary>
		[XmlIgnore]
		internal string PlainPassword
		{
			get { return password; }
			set
			{
				if (password != value)
				{
					password = value;
					saveSettingsFromChange();
					RaiseCredentialsChangedEvent();
				}
			}
		}

		/// <summary>
		/// Save the username to the settings file?
		/// </summary>
		public bool SaveUsername
		{
			get { return saveUsername; }
			set
			{
				if (saveUsername != value)
				{
					saveUsername = value;
					saveSettingsFromChange();
				}
			}
		}

		/// <summary>
		/// Save the password to the settings file?
		/// </summary>
		public bool SavePassword
		{
			get { return savePassword; }
			set
			{
				if (savePassword != value)
				{
					savePassword = value;
					saveSettingsFromChange();
				}
			}
		}

		/// <summary>
		/// Automatically check for new versions?
		/// </summary>
		public bool CheckForNewVersions
		{
			get { return checkForNewVersions; }
			set
			{
				if (checkForNewVersions != value)
				{
					checkForNewVersions = value;
					saveSettingsFromChange();
				}
			}
		}

		/// <summary>
		/// Start login when JetLoginTool starts?
		/// </summary>
		public bool LoginOnStart
		{
			get { return loginOnStart; }
			set
			{
				if (loginOnStart != value)
				{
					loginOnStart = value;
					saveSettingsFromChange();
					RaiseCredentialsChangedEvent();
				}
			}
		}

		/// <summary>
		/// Start the JetLoginTool minimised?
		/// </summary>
		public bool StartMinimised
		{
			get { return startMinimised; }
			set
			{
				if (startMinimised != value)
				{
					startMinimised = value;
					saveSettingsFromChange();
				}
			}
		}

		/// <summary>
		/// Start the JetLoginTool when Windows starts?
		/// </summary>
		public bool StartWithWindows
		{
			get { return startWithWindows; }
			set
			{
				if (startWithWindows != value)
				{
					startWithWindows = value;
					saveSettingsFromChange();
				}
			}
		}

		/// <summary>
		/// Name of the location to use (from locations.xml)
		/// </summary>
		public string LocationName
		{
			get { return locationName; }
			set
			{
				if (locationName != value)
				{
					locationName = value;
					SetCurrentLocation();
					saveSettingsFromChange();
					RaiseLocationChangedEvent();
				}
			}
		}

		/// <summary>
		/// Timeout, in milliseconds, to show the notification balloon when successfully logged in
		/// </summary>
		public int SuccessBalloonTimeout
		{
			get { return successBalloonTimeout; }
			set
			{
				if (successBalloonTimeout != value)
				{
					successBalloonTimeout = value;
					saveSettingsFromChange();
				}
			}
		}

		/// <summary>
		/// Timeout, in milliseconds, to show the notification balloon when an error occurs
		/// </summary>
		public int ErrorBalloonTimeout
		{
			get { return errorBalloonTimeout; }
			set
			{
				if (errorBalloonTimeout != value)
				{
					errorBalloonTimeout = value;
					saveSettingsFromChange();
				}
			}
		}

		/// <summary>
		/// The current location to use
		/// </summary>
		[XmlIgnore]
		public Location CurrentLocation { get; private set; }

		/// <summary>
		/// Suppress the settings from auto-saving
		/// </summary>
		[XmlIgnore]
		public bool SuppressSaving { get; set; }

		/// <summary>
		/// List of possible locations and their settings
		/// </summary>
		[XmlIgnore]
		public List<Location> Locations { get; private set; }
		#endregion
		#region Methods
		internal void SetCurrentLocation()
		{
			CurrentLocation = null;
			if (Locations != null)
			{
				int counter = 0;
				while ((CurrentLocation == null) && (counter < Locations.Count))
				{
					if (Locations[counter].Name == locationName)
					{
						CurrentLocation = Locations[counter];
					}
					counter++;
				}

				if (CurrentLocation == null)
				{
					CurrentLocation = Locations[0];
				}
			}
		}

		private void saveSettingsFromChange()
		{
			if (!SuppressSaving)
			{
				SaveSettings();
			}
		}

		public void SaveSettings()
		{
			XmlSerializer engineSerialize = new XmlSerializer(typeof(JetSettings));
			JetSettings copySettings = new JetSettings(this) { SuppressSaving = true };
			if (!SaveUsername)
			{
				copySettings.Username = "";
			}
			if (!SavePassword)
			{
				copySettings.PlainPassword = "";
			}

			try
			{
				settingsFile.Directory.Create();
				using (Stream fileStream = settingsFile.Open(FileMode.Create))
				{
					engineSerialize.Serialize(fileStream, copySettings);
				}
			}
			catch (SystemException)
			{ }
		}

		public static JetSettings loadSettings()
		{
			XmlSerializer engineSerialize = new XmlSerializer(typeof(JetSettings));
			JetSettings output = null;

			try
			{
				using (Stream fileStream = settingsFile.OpenRead())
				{
					output = (JetSettings)engineSerialize.Deserialize(fileStream);
				}
			}
			catch (SystemException)
			{
				output = null;
			}

			if (output == null)
			{
				output = checkForOldSettings();
				output.SaveSettings();
			}
			output.SetCurrentLocation();

			return output;
		}

		private static JetSettings checkForOldSettings()
		{
			JetSettings output = new JetSettings();
			DirectoryInfo[] versionDir = ((new DirectoryInfo(Application.LocalUserAppDataPath)).Parent).GetDirectories();
			XmlSerializer engineSerialize = new XmlSerializer(typeof(JetSettings));

			bool success = false;
			int counter = 0;

			while ((counter < versionDir.Length) && (!success))
			{
				FileInfo settingsFile = new FileInfo(versionDir[counter].FullName + "\\" + SETTINGS_FILE);

				if (settingsFile.Exists)
				{
					try
					{
						using (Stream fileStream = settingsFile.OpenRead())
						{
							output = (JetSettings)engineSerialize.Deserialize(fileStream);
							success = true;
						}
					}
					catch (SystemException)
					{}
				}

				try
				{
					versionDir[counter].Delete(true);
				}
				catch (SystemException)
				{}

				counter++;
			}

			while (counter < versionDir.Length)
			{
				try
				{
					versionDir[counter].Delete(true);
				}
				catch (SystemException)
				{ }
				counter++;
			}

			return output;
		}
		#endregion
		#region Events
		public event EventHandler CredentialsChanged;
		private void RaiseCredentialsChangedEvent()
		{
			if (CredentialsChanged != null)
			{
				CredentialsChanged.Invoke(this, new EventArgs());
			}
		}

		public event EventHandler LocationChanged;
		private void RaiseLocationChangedEvent()
		{
			if (LocationChanged != null)
			{
				LocationChanged.Invoke(this, new EventArgs());
			}
		}
		#endregion
	}
}
